package com.weathereport.entity;

import java.util.ArrayList;

public class Armario {
	
	public final static int CALCADO = 0;
	public final static int ROUPA_INTIMA = 1;
	public final static int NORMAL_BAIXO = 2;
	public final static int NORMAL_CIMA = 3;
	public final static int SEGUNDA_CAMADA_CIMA = 4;
	public final static int SEGUNDA_PELE_CIMA = 5;
	public final static int SEGUNDA_PELE_BAIXO = 6;
	public final static int TERCEIRA_CAMADA_CIMA = 7;
	
	public final static int PRIMEIRA_CAMADA = CALCADO;
	public final static int ULTIMA_CAMADA = TERCEIRA_CAMADA_CIMA;
	
	public static Armario instancia;
	
	/**
     * 0 - roupas intimas
     * 1 - normal parte de cima 
     * 2 - normal parte de baixo
     * 3 - segunda camada parte de cima
     * 4 - segunda pele parte de cima
     * 5 - segunda pele parte de baixo 
     * 6 - terceira camada parte de cima
     */
	private ArrayList<ArrayList<Roupa>> armario;
	
	public Armario() {
		armario = new ArrayList<ArrayList<Roupa>>();
		for (int i = PRIMEIRA_CAMADA; i <= ULTIMA_CAMADA; i++) {
			armario.add(new ArrayList<Roupa>());
		}
		
		inicializarRoupas();
	}
	
	public void addRoupa(Roupa roupa, int nivel) {
		armario.get(nivel).add(roupa);
	}
	
	public void removeRoupa(Roupa roupa, int nivel) {
		armario.get(nivel).remove(roupa);
	}
	
	public ArrayList<Roupa> getRoupas(int nivel) {
		return armario.get(nivel);
	}
	
	public ArrayList<Roupa> escolheRoupasArmario(double clo) {
		ArrayList<Roupa> vestimenta = new ArrayList<Roupa>();
		
		// Algoritmo novo
		int ordem = 0;
		int ultimaInsOrdem = 0;
		boolean escolhendo = true;
		while (escolhendo) {
			// Varre todas as camadas, buscando melhor combinação de acordo com a hierarquia
			int verifica = -1;
			for (int i = Armario.PRIMEIRA_CAMADA; i <= Armario.ULTIMA_CAMADA; i++) {
				ArrayList<Roupa> roupas =  getRoupas(i);
				// Pega resistencia termica da vestimenta atual para aquela camada
				double resistenciaAtual = 0;
				if (vestimenta.size() > i) {
					resistenciaAtual = vestimenta.get(i).getResistenciaTermica();
				}

				// Escolhe a roupa mais fria, porém mais quente que a que já está em uso
				double maisFria = 1000; // TODO - tem que ser um valor mais alto que todos
				int indice = -1;				
				for (int x = 0; x < roupas.size(); x++) {
					if (roupas.get(x).getOrdem() == ordem) {
						if ((roupas.get(x).getResistenciaTermica() > resistenciaAtual) &&
						   (roupas.get(x).getResistenciaTermica() < maisFria))	{
							indice = x;
							maisFria = roupas.get(x).getResistenciaTermica();
						}
					}
				}
			
				// Troca vestimenta se a sensação térmica melhorar
				if (indice >= 0) {
					@SuppressWarnings("unchecked")
					ArrayList<Roupa> vestimentaTmp = (ArrayList<Roupa>) vestimenta.clone(); 
					colocarParteVestimenta(vestimentaTmp, roupas.get(indice), i);
					
					if (Math.abs(clo - calcularCloVestimenta(vestimentaTmp)) < 
						Math.abs(clo - calcularCloVestimenta(vestimenta))) {
						ultimaInsOrdem = ordem;
						vestimenta = vestimentaTmp;
					} else {
						verifica++;
					}
				} else {
					verifica++;
				}
			}
			// Se passou por todas as camadas e não trocou de roupa, aumenta a ordem
			if (verifica == Armario.ULTIMA_CAMADA) {
				ordem++;
			}
			
			// Se já esta na última ordem, terminou o algoritmo
			if ((ordem - ultimaInsOrdem > 1) || (ordem > 7)) { // TODO - criar constante
				escolhendo = false;
			}
		}
		
		// Algoritmo antigo
		/*for (int i = Armario.PRIMEIRA_CAMADA; i <= Armario.ULTIMA_CAMADA; i++) {
			ArrayList<Roupa> roupas =  getRoupas(i);
			double roupaMaisQuente = 0;
			int indice = -1;
			double cloAtual = 0;
			
			for (int x = 0; x < roupas.size(); x++) {
				cloAtual = roupas.get(x).getResistenciaTermica();
				if (cloAtual > roupaMaisQuente) {
					if (clo - cloAtual > 0) {
						indice = x;
						roupaMaisQuente = cloAtual;
					}
				}
			}
			
			if (indice == -1) {
				break;
			} else {
				clo -= roupas.get(indice).getResistenciaTermica();
				vestimenta.add(roupas.get(indice));
			}
		}*/
		
		return vestimenta;
	}
	
	private void colocarParteVestimenta(ArrayList<Roupa> vestimenta, Roupa roupa, int nivel) {
		// TODO - arrumar para não parecer tao xunxo
		while (nivel >= vestimenta.size()) {
			vestimenta.add(new Roupa(-1, "", 'A', 0, 0));
		}
			
		vestimenta.set(nivel, roupa);
	}
	
	private double calcularCloVestimenta(ArrayList<Roupa> vestimenta) {
		double clo = 0;
	
		for (int i = 0; i < vestimenta.size(); i++) {
			clo += vestimenta.get(i).getResistenciaTermica();
		}
		
		return clo;
	}
	
	private void inicializarRoupas() {
		Roupa roupa;
		
		roupa = new Roupa(1, "Cueca", 'M', 0.05, 0);
		addRoupa(roupa, Armario.ROUPA_INTIMA);
		
		roupa = new Roupa(2, "Camiseta sem mangas", 'M', 0.06, 1);
		addRoupa(roupa, Armario.NORMAL_CIMA);
		
		roupa = new Roupa(3, "Camiseta leve mangas curtas", 'M', 0.14, 1);
		addRoupa(roupa, Armario.NORMAL_CIMA);
		
		roupa = new Roupa(4, "Camiseta leve mangas compridas", 'M', 0.19, 4);
		addRoupa(roupa, Armario.NORMAL_CIMA);
		
		roupa = new Roupa(5, "Camiseta pesada mangas curtas", 'M', 0.25, 3);
		addRoupa(roupa, Armario.NORMAL_CIMA);
		
		roupa = new Roupa(6, "Camiseta pesada mangas compridas", 'M', 0.29, 5);
		addRoupa(roupa, Armario.NORMAL_CIMA);
		
		roupa = new Roupa(7, "Casaco leve", 'M', 0.32, 4);
		addRoupa(roupa, Armario.SEGUNDA_CAMADA_CIMA);
		
		roupa = new Roupa(8, "Casaco pesado", 'M', 0.49, 5);
		addRoupa(roupa, Armario.SEGUNDA_CAMADA_CIMA);
		
		roupa = new Roupa(9, "Blusão leve", 'M', 0.17, 4);
		addRoupa(roupa, Armario.SEGUNDA_CAMADA_CIMA);
		
		roupa = new Roupa(10, "Blusão pesado", 'M', 0.37, 5);
		addRoupa(roupa, Armario.SEGUNDA_CAMADA_CIMA);
		
		roupa = new Roupa(11, "Calça leve", 'M', 0.26, 2);
		addRoupa(roupa, Armario.NORMAL_BAIXO);
		
		roupa = new Roupa(12, "Calça pesada", 'M', 0.36, 3);
		addRoupa(roupa, Armario.NORMAL_BAIXO);
		
		roupa = new Roupa(13, "Ceroula", 'M', 0.12, 6);
		addRoupa(roupa, Armario.SEGUNDA_PELE_BAIXO);
		
		roupa = new Roupa(14, "Casacão", 'M', 0.49, 7);
		addRoupa(roupa, Armario.TERCEIRA_CAMADA_CIMA);
		
		roupa = new Roupa(15, "Bermuda", 'M', 0.11, 1);
		addRoupa(roupa, Armario.NORMAL_BAIXO);
		
		roupa = new Roupa(16, "Chinelo", 'M', 0.02, 1);
		addRoupa(roupa, Armario.CALCADO);
		
		roupa = new Roupa(17, "Meias e tênis", 'M', 0.04 + 0.03, 2);
		addRoupa(roupa, Armario.CALCADO);
		
		roupa = new Roupa(18, "Meias de lã e tênis", 'M', 0.04 + 0.04, 6);
		addRoupa(roupa, Armario.CALCADO);
		
		roupa = new Roupa(19, "Short", 'M', 0.08, 1);
		addRoupa(roupa, Armario.NORMAL_BAIXO);
		
		roupa = new Roupa(20, "Camiseta segunda pele mangas curtas", 'M', 0.10, 6);
		addRoupa(roupa, Armario.SEGUNDA_PELE_CIMA);
		
		roupa = new Roupa(20, "Camiseta segunda pele mangas compridas", 'M', 0.12, 6);
		addRoupa(roupa, Armario.SEGUNDA_PELE_CIMA);
	}
	
	public static Armario getInstance() {
		if (instancia == null) {
			createInstance();
		}
		
		return instancia;
	}
	
	public static Armario createInstance() {
		instancia = new Armario();
		
		return instancia;
	}
	
}